#include "stdafx.h"
#include "StockService.h"
#include "Security.h"
#include "FCTran.h"
#include "DataCenter.h"

int StockService::dayOfWeek(int y, int m, int d){
    if (m == 1 || m == 2)
    {
        m += 12;
        y--;
    }
    return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
}

int StockService::getSeason(int month){
    if (month >= 1 && month <= 3)
    {
        return 1;
    }
    else if (month >= 4 && month <= 6)
    {
        return 2;
    }
    else if (month >= 7 && month <= 9)
    {
        return 3;
    }
    else
    {
        return 4;
    }
}

void StockService::mergeLatestData(String code, ArrayList<SecurityData> *oldDatas, SecurityData latestData, ClientTickDataCache *tickDataCache, int dCycle){
    int cycle = dCycle;
    if (cycle == 0)
    {
        cycle = 1;
    }
    if (latestData.m_open <= 0 || latestData.m_volume <= 0 || latestData.m_amount <= 0)
    {
        return;
    }
    int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, ms = 0;
    FCTran::getDateByNum(latestData.m_date, &year, &month, &day, &hour, &minute, &second, &ms);
    if (hour * 60 + minute < 570)
    {
        latestData.m_date = FCTran::getDateNum(year, month, day, 9, 30, 0, 0);
    }
    else if (hour * 60 + minute < 571)
    {
        latestData.m_date = FCTran::getDateNum(year, month, day, 9, 31, 0, 0);
    }
    else if (hour * 60 + minute > 900)
    {
        latestData.m_date = FCTran::getDateNum(year, month, day, 15, 0, 0, 0);
    }
    else if (hour * 60 + minute > 690 && hour * 60 + minute < 780)
    {
        FCTran::getDateNum(year, month, day, 11, 30, 0, 0);
    }
    bool isNextCycle = true;
    if (dCycle == 0)
    {
        isNextCycle = false;
    }
    else if (cycle < 1440)
    {
        if (oldDatas->size() > 0)
        {
            int newMinutes = (int)(latestData.m_date / 60);
            int lastMinutes = (int)(oldDatas->get(oldDatas->size() - 1).m_date / 60);
            isNextCycle = newMinutes - lastMinutes >= cycle;
        }
    }
    else
    {
        if (cycle == 1440)
        {
            if (oldDatas->size() > 0)
            {
                int lyear = 0, lmonth = 0, lday = 0, lhour = 0, lminute = 0, lsecond = 0, lms = 0;
                FCTran::getDateByNum(oldDatas->get(oldDatas->size() - 1).m_date, &lyear, &lmonth, &lday, &lhour, &lminute, &lsecond, &lms);
                isNextCycle = FCTran::getDateNum(year, month, day, 0, 0, 0, 0)
                != FCTran::getDateNum(lyear, lmonth, lday, 0, 0, 0, 0) ;
            }
        }
        else if (cycle == 10080)
        {
            if (oldDatas->size() > 0)
            {
                double firstDate = FCTran::getDateNum(1970, 1, 5, 0, 0, 0, 0);
                int lWeeks = (int)((oldDatas->get(oldDatas->size() - 1).m_date - firstDate) / 86400) / 7;
                int weeks = (int)((latestData.m_date - firstDate) / 86400) / 7;
                if (weeks > lWeeks)
                {
                    isNextCycle = true;
                }
                else
                {
                    isNextCycle = false;
                }
            }
        }
        else if (cycle == 43200)
        {
            if (oldDatas->size() > 0)
            {
                int lyear = 0, lmonth = 0, lday = 0, lhour = 0, lminute = 0, lsecond = 0, lms = 0;
                FCTran::getDateByNum(oldDatas->get(oldDatas->size() - 1).m_date, &lyear, &lmonth, &lday, &lhour, &lminute, &lsecond, &lms);
                isNextCycle = (year * 12 + month != lyear * 12 + lmonth);
            }
        }
        else if (cycle == 129600)
        {
            if (oldDatas->size() > 0)
            {
                int lyear = 0, lmonth = 0, lday = 0, lhour = 0, lminute = 0, lsecond = 0, lms = 0;
                FCTran::getDateByNum(oldDatas->get(oldDatas->size() - 1).m_date, &lyear, &lmonth, &lday, &lhour, &lminute, &lsecond, &lms);
                isNextCycle = year * 4 + getSeason(month) != lyear * 4 + getSeason(lmonth);
            }
        }
        else if (cycle == 259200)
        {
            if (oldDatas->size() > 0)
            {
                int lyear = 0, lmonth = 0, lday = 0, lhour = 0, lminute = 0, lsecond = 0, lms = 0;
                FCTran::getDateByNum(oldDatas->get(oldDatas->size() - 1).m_date, &lyear, &lmonth, &lday, &lhour, &lminute, &lsecond, &lms);
                isNextCycle = year * 2 + (month - 1) / 6 != lyear * 2 + (lmonth - 1) / 6;
            }
        }
        else if (cycle == 518400)
        {
            if (oldDatas->size() > 0)
            {
                int lyear = 0, lmonth = 0, lday = 0, lhour = 0, lminute = 0, lsecond = 0, lms = 0;
                FCTran::getDateByNum(oldDatas->get(oldDatas->size() - 1).m_date, &lyear, &lmonth, &lday, &lhour, &lminute, &lsecond, &lms);
                isNextCycle = year != lyear;
            }
        }
    }
    if (isNextCycle)
    {
        SecurityData newCycleData;
        if (cycle < 1440)
        {
            newCycleData.m_date = FCTran::getDateNum(year, month, day, hour, minute, 0, 0);
        }
        else
        {
            newCycleData.m_date = FCTran::getDateNum(year, month, day, 0, 0, 0, 0);
        }
        newCycleData.m_close = latestData.m_close;
        newCycleData.m_high = latestData.m_close;
        newCycleData.m_low = latestData.m_close;
        newCycleData.m_open = latestData.m_close;
        newCycleData.m_volume = latestData.m_volume - tickDataCache->m_lastVolume;
        newCycleData.m_amount = latestData.m_amount - tickDataCache->m_lastAmount;
        oldDatas->add(newCycleData);
    }
    else
    {
        if (oldDatas->size() > 0)
        {
            int pos = oldDatas->size() - 1;
            SecurityData lastCycleData = oldDatas->get(pos);
            if (dCycle == 0)
            {
                double newData = FCTran::getDateNum(year, month, day, hour, minute, second, 0);
                for (int i = 0; i < oldDatas->size(); i++)
                {
                    SecurityData oData = oldDatas->get(i);
                    if (oData.m_date == newData)
                    {
                        oData.m_open = latestData.m_open;
                        lastCycleData = oData;
                        oldDatas->set(i, oData);
                        pos = i;
                        break;
                    }
                }
            }
            lastCycleData.m_close = latestData.m_close;
            if (lastCycleData.m_high < latestData.m_close)
            {
                lastCycleData.m_high = latestData.m_close;
            }
            if (lastCycleData.m_low > lastCycleData.m_close)
            {
                lastCycleData.m_low = latestData.m_close;
            }
            lastCycleData.m_amount += latestData.m_amount - tickDataCache->m_lastAmount;
            lastCycleData.m_volume += latestData.m_volume - tickDataCache->m_lastVolume;
            oldDatas->set(pos, lastCycleData);
        }
    }
    tickDataCache->m_code = code;
    tickDataCache->m_lastAmount = latestData.m_amount;
    tickDataCache->m_lastDate = latestData.m_date;
    tickDataCache->m_lastVolume = latestData.m_volume;
}

double StockService::fq_price_func(double price, ADJUSTMENTFACTOR *factor){
    float cash_bt = factor->f1;
    float bonus_shr = factor->f3;
    float allot_pct = factor->f4;
    float allot_price = factor->f2;
    return (10.0 * price - cash_bt + allot_pct * allot_price) / (10.0 + allot_pct + bonus_shr);
}

double StockService::fq_price_func2(double price, ADJUSTMENTFACTOR *factor)
{
    float cash_bt = factor->f1;
    float bonus_shr = factor->f3;
    float allot_pct = factor->f4;
    float allot_price = factor->f2;
    return (price * (10.0 + allot_pct + bonus_shr) - allot_pct * allot_price + cash_bt) / 10.0;
}

void StockService::ConvertXDRBeforePrice(String code, SecurityData *kd, double trade_date, ArrayList<ADJUSTMENTFACTOR*> *factor)
{
    int size = factor->size();
    if (size > 0)
    {
        int pos = 0;
        double date = kd->m_date;
        if (kd->m_date < factor->get(factor->size() - 1)->dwDate)
        {
            for (int i = 0; i < size; i++)
            {
                if (trade_date > 0 && trade_date < factor->get(i)->dwDate)
                {
                    continue;
                }
                pos = i;
                if (date < factor->get(i)->dwDate)
                {
                    break;
                }
            }
            for (int i = pos; i < size; i++)
            {
                if (trade_date > 0 && trade_date < factor->get(i)->dwDate)
                {
                    continue;
                }
                kd->m_open = fq_price_func(kd->m_open, factor->get(i));
                kd->m_high = fq_price_func(kd->m_high, factor->get(i));
                kd->m_low = fq_price_func(kd->m_low, factor->get(i));
                kd->m_close = fq_price_func(kd->m_close, factor->get(i));
            }
        }
    }
}

void StockService::ConvertXDRAfterPrice(String code, SecurityData *kd, double trade_date, ArrayList<ADJUSTMENTFACTOR*> *factor){
    int size = factor->size();
    if (size > 0)
    {
        double date = kd->m_date;
        ArrayList<ADJUSTMENTFACTOR*> factors;
        for (int i = 0; i < size; i++)
        {
            if (date < factor->get(i)->dwDate)
            {
                break;
            }
            else
            {
                factors.insert(0, factor->get(i));
            }
        }
        for (int i = 0; i < factors.size(); i++)
        {
            kd->m_open = fq_price_func2(kd->m_open, factors.get(i));
            kd->m_high = fq_price_func2(kd->m_high, factors.get(i));
            kd->m_low = fq_price_func2(kd->m_low, factors.get(i));
            kd->m_close = fq_price_func2(kd->m_close, factors.get(i));
        }
        factors.clear();
    }
}

void StockService::ConvertXDR(String code, int rights_offering, ArrayList<SecurityData> *datas)
{
    HashMap<String, ArrayList<ADJUSTMENTFACTOR*>> factors = DataCenter::getHistoryServiceClient()->m_factors;
    if (factors.containsKey(code))
    {
        ArrayList<ADJUSTMENTFACTOR*> factor = factors.get(code);
        int datasSize = datas->size();
        if (datasSize > 0)
        {
            double trade_date = datas->get(datas->size() - 1).m_date;
            // 复权K线
            for (int i = 0; i < datasSize; ++i)
            {
                SecurityData kd = datas->get(i);
                if (rights_offering == 1)
                {
                    ConvertXDRBeforePrice(code, &kd, trade_date, &factor);
                }
                else if (rights_offering == 2)
                {
                    ConvertXDRAfterPrice(code, &kd, trade_date, &factor);
                }
                datas->set(i, kd);
            }
        }
    }
}

void StockService::multiMinuteSecurityDatas(ArrayList<SecurityData> *newDatas, ArrayList<SecurityData> *minuteDatas, int cycle)
        {
            int lastMinutes = 0;
            for (int i = 0; i < minuteDatas->size(); i++)
            {
                SecurityData minuteData = minuteDatas->get(i);
                int minutes = (int)(minuteData.m_date / 60);
                if (lastMinutes == 0)
                {
                    lastMinutes = minutes;
                }
                //更新
                if (newDatas->size() > 0 && minutes - lastMinutes < cycle)
                {
                    SecurityData lastData = newDatas->get(newDatas->size() - 1);
                    lastData.m_close = minuteData.m_close;
                    if (minuteData.m_high > lastData.m_high)
                    {
                        lastData.m_high = minuteData.m_high;
                    }
                    if (minuteData.m_low < lastData.m_low)
                    {
                        lastData.m_low = minuteData.m_low;
                    }
                    lastData.m_amount += minuteData.m_amount;
                    lastData.m_volume += minuteData.m_volume;
                    lastData.m_endDate = minuteData.m_date;
                    newDatas->set(newDatas->size() - 1, lastData);
                }
                else
                {
                    SecurityData newData;
                    newData.m_date = minuteData.m_date;
                    newData.m_high = minuteData.m_high;
                    newData.m_low = minuteData.m_low;
                    newData.m_open = minuteData.m_open;
                    newData.m_close = minuteData.m_close;
                    newData.m_amount = minuteData.m_amount;
                    newData.m_volume = minuteData.m_volume;
                    newData.m_startDate = minuteData.m_date;
                    newData.m_endDate = minuteData.m_date;
                    newDatas->add(newData);
                    lastMinutes = minutes;
                }
            }
        }

int StockService::getHistoryWeekDatas(ArrayList<SecurityData> *weekDatas, ArrayList<SecurityData> *dayDatas)
{
    int dayDatasSize = dayDatas->size();
    if (dayDatasSize > 0)
    {
        double firstDate = FCTran::getDateNum(1970, 1, 5, 0, 0, 0, 0);
        SecurityData weekData;
        weekData = dayDatas->get(0);
        weekData.m_startDate = weekData.m_date;
        int lWeeks = (int)((weekData.m_date - firstDate) / 86400 / 7);
        for (int i = 0; i < dayDatasSize; i++)
        {
            SecurityData dayData;
            dayData = dayDatas->get(i);
            int weeks = (int)((dayData.m_date - firstDate) / 86400 / 7);
            bool isNextWeek = false;
            if (weeks > lWeeks)
            {
                isNextWeek = true;
            }
            if (isNextWeek)
            {
                weekDatas->add(weekData);
                weekData = dayData;
                weekData.m_startDate = weekData.m_date;
                if (i == dayDatasSize - 1)
                {
                    weekData.m_endDate = dayData.m_date;
                    weekDatas->add(weekData);
                }
            }
            else
            {
                if (i > 0)
                {
                    weekData.m_endDate = dayData.m_date;
                    weekData.m_close = dayData.m_close;
                    weekData.m_amount += dayData.m_amount;
                    weekData.m_volume += dayData.m_volume;
                    if (weekData.m_high < dayData.m_high)
                    {
                        weekData.m_high = dayData.m_high;
                    }
                    if (weekData.m_low > dayData.m_low)
                    {
                        weekData.m_low = dayData.m_low;
                    }
                }
                if (i == dayDatasSize - 1)
                {
                    weekData.m_endDate = dayData.m_date;
                    weekDatas->add(weekData);
                }
            }
            lWeeks = weeks;
        }
    }
    return 1;
}

int StockService::getHistoryMonthDatas(ArrayList<SecurityData> *monthDatas, ArrayList<SecurityData> *dayDatas){
    int dayDatasSize = dayDatas->size();
    if (dayDatasSize > 0)
    {
        SecurityData monthData;
        monthData = dayDatas->get(0);
        monthData.m_startDate = monthData.m_date;
        int lYear = 0, lMonth = 0, lDay = 0, lHour = 0, lMinute = 0, lSecond = 0, lMs = 0;
        FCTran::getDateByNum(monthData.m_date, &lYear, &lMonth, &lDay, &lHour, &lMinute, &lSecond, &lMs);
        for (int i = 0; i < dayDatasSize; i++)
        {
            SecurityData dayData;
            dayData = dayDatas->get(i);
            int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, ms = 0;
            FCTran::getDateByNum(dayData.m_date,  &year,  &month,  &day,  &hour,  &minute,  &second,  &ms);
            bool isNextMonth = year * 12 + month > lYear * 12 + lMonth;
            if (isNextMonth)
            {
                monthDatas->add(monthData);
                monthData = dayData;
                monthData.m_startDate = monthData.m_date;
                if (i == dayDatasSize - 1)
                {
                    monthData.m_endDate = dayData.m_date;
                    monthDatas->add(monthData);
                }
            }
            else
            {
                if (i > 0)
                {
                    monthData.m_endDate = dayData.m_date;
                    monthData.m_close = dayData.m_close;
                    monthData.m_amount += dayData.m_amount;
                    monthData.m_volume += dayData.m_volume;
                    if (monthData.m_high < dayData.m_high)
                    {
                        monthData.m_high = dayData.m_high;
                    }
                    if (monthData.m_low > dayData.m_low)
                    {
                        monthData.m_low = dayData.m_low;
                    }
                }
                if (i == dayDatasSize - 1)
                {
                    monthData.m_endDate = dayData.m_date;
                    monthDatas->add(monthData);
                }
            }
            lYear = year;
            lMonth = month;
            lDay = day;
        }
    }
    return 1;
}

int StockService::getHistorySeasonDatas(ArrayList<SecurityData> *seasonDatas, ArrayList<SecurityData> *dayDatas)
{
    int dayDatasSize = dayDatas->size();
    if (dayDatasSize > 0)
    {
        SecurityData seaonData;
        seaonData = dayDatas->get(0);
        seaonData.m_startDate = seaonData.m_date;
        int lYear = 0, lMonth = 0, lDay = 0, lHour = 0, lMinute = 0, lSecond = 0, lMs = 0;
        FCTran::getDateByNum(seaonData.m_date,  &lYear,  &lMonth,  &lDay,  &lHour,  &lMinute,  &lSecond,  &lMs);
        for (int i = 0; i < dayDatasSize; i++)
        {
            SecurityData dayData;
            dayData = dayDatas->get(i);
            int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, ms = 0;
            FCTran::getDateByNum(dayData.m_date,  &year,  &month,  &day, &hour,  &minute,  &second,  &ms);
            bool isNextSeason = year * 4 + getSeason(month) > lYear * 4 + getSeason(lMonth);
            if (isNextSeason)
            {
                seasonDatas->add(seaonData);
                seaonData = dayData;
                seaonData.m_startDate = seaonData.m_date;
                if (i == dayDatasSize - 1)
                {
                    seaonData.m_endDate = dayData.m_date;
                    seasonDatas->add(seaonData);
                }
            }
            else
            {
                if (i > 0)
                {
                    seaonData.m_endDate = dayData.m_date;
                    seaonData.m_close = dayData.m_close;
                    seaonData.m_amount += dayData.m_amount;
                    seaonData.m_volume += dayData.m_volume;
                    if (seaonData.m_high < dayData.m_high)
                    {
                        seaonData.m_high = dayData.m_high;
                    }
                    if (seaonData.m_low > dayData.m_low)
                    {
                        seaonData.m_low = dayData.m_low;
                    }
                }
                if (i == dayDatasSize - 1)
                {
                    seaonData.m_endDate = dayData.m_date;
                    seasonDatas->add(seaonData);
                }
            }
            lYear = year;
            lMonth = month;
            lDay = day;
        }
    }
    return 1;
}

int StockService::getHistoryHalfYearDatas(ArrayList<SecurityData> *halfYearDatas, ArrayList<SecurityData> *dayDatas){
    int dayDatasSize = dayDatas->size();
    if (dayDatasSize > 0)
    {
        SecurityData yearData;
        yearData = dayDatas->get(0);
        yearData.m_startDate = yearData.m_date;
        int lYear = 0, lMonth = 0, lDay = 0, lHour = 0, lMinute = 0, lSecond = 0, lMs = 0;
        FCTran::getDateByNum(yearData.m_date, &lYear, &lMonth, &lDay, &lHour, &lMinute, &lSecond, &lMs);
        for (int i = 0; i < dayDatasSize; i++)
        {
            SecurityData dayData;
            dayData = dayDatas->get(i);
            int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, ms = 0;
            FCTran::getDateByNum(dayData.m_date, &year, &month, &day, &hour, &minute, &second, &ms);
            bool isNextHalfYear = year * 2 + (month - 1) / 6 > lYear * 2 + (lMonth - 1) / 6;
            if (isNextHalfYear)
            {
                halfYearDatas->add(yearData);
                yearData = dayData;
                yearData.m_startDate = yearData.m_date;
                if (i == dayDatasSize - 1)
                {
                    yearData.m_endDate = dayData.m_date;
                    halfYearDatas->add(yearData);
                }
            }
            else
            {
                if (i > 0)
                {
                    yearData.m_endDate = dayData.m_date;
                    yearData.m_close = dayData.m_close;
                    yearData.m_amount += dayData.m_amount;
                    yearData.m_volume += dayData.m_volume;
                    if (yearData.m_high < dayData.m_high)
                    {
                        yearData.m_high = dayData.m_high;
                    }
                    if (yearData.m_low > dayData.m_low)
                    {
                        yearData.m_low = dayData.m_low;
                    }
                }
                if (i == dayDatasSize - 1)
                {
                    yearData.m_endDate = dayData.m_date;
                    halfYearDatas->add(yearData);
                }
            }
            lYear = year;
            lMonth = month;
            lDay = day;
        }
    }
    return 1;
}

int StockService::getHistoryYearDatas(ArrayList<SecurityData> *yearDatas, ArrayList<SecurityData> *dayDatas){
    int dayDatasSize = dayDatas->size();
    if (dayDatasSize > 0)
    {
        SecurityData yearData = dayDatas->get(0);
        yearData.m_startDate = yearData.m_date;
        int lYear = 0, lMonth = 0, lDay = 0, lHour = 0, lMinute = 0, lSecond = 0, lMs = 0;
        FCTran::getDateByNum(yearData.m_date, &lYear, &lMonth, &lDay, &lHour, &lMinute, &lSecond, &lMs);
        for (int i = 0; i < dayDatasSize; i++)
        {
            SecurityData dayData;
            dayData = dayDatas->get(i);
            //            dayData.copy(dayDatas.get(i));
            int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, ms = 0;
            FCTran::getDateByNum(dayData.m_date, &year, &month, &day, &hour, &minute, &second, &ms);
            bool isNextYear = year > lYear;
            if (isNextYear)
            {
                yearDatas->add(yearData);
                yearData = dayData;
                yearData.m_startDate = yearData.m_date;
                if (i == dayDatasSize - 1)
                {
                    yearData.m_endDate = dayData.m_date;
                    yearDatas->add(yearData);
                }
            }
            else
            {
                if (i > 0)
                {
                    yearData.m_endDate = dayData.m_date;
                    yearData.m_close = dayData.m_close;
                    yearData.m_amount += dayData.m_amount;
                    yearData.m_volume += dayData.m_volume;
                    if (yearData.m_high < dayData.m_high)
                    {
                        yearData.m_high = dayData.m_high;
                    }
                    if (yearData.m_low > dayData.m_low)
                    {
                        yearData.m_low = dayData.m_low;
                    }
                }
                if (i == dayDatasSize - 1)
                {
                    yearData.m_endDate = dayData.m_date;
                    yearDatas->add(yearData);
                }
            }
            lYear = year;
            lMonth = month;
            lDay = day;
        }
    }
    return 1;
}
